function mlhMain() {

    //список загруженных шаблонов
    this.templates = [];

    //полушение шаблона
    this.getTemplate = function(file, callback) {
        var this_ = this;
        if ($.inArray(file, this.templates) < 0) {
            $.ajax(
                {
                    url: file,
                    dataType: 'text',
                    success: function (templateBody) {
                        this_.templates.push(file);
                        try {
                            $(templateBody.split('<!-- TEMPLATE ')).each(function() {
                                var templateName = this.split('-->')[0];
                                var templateText = this.substr(templateName.length + 3);
                                $.template($.trim(templateName), $.trim(templateText));
                            });
                            if (app.debug.template) console.log("Loaded " + file);
                            var success = true;
                        } catch (e) {
                            if (app.debug.template)console.log("Can't parse " + file + "\n" + e.message);
                            success = false;
                        }
                        if (typeof(callback) === 'function') {
                            callback(success);
                        }
                    },
                    error: function() {
                        if (app.debug.template) console.log("Can't load " + file);
                        callback(false);
                    }
                }
            );
        } else {
            if (app.debug.template) console.log("Get template " + file + " from cache");
            callback(true);
        }
    }

    //список подписанных событий
    var observers = new Array;

    //подписаться на событие
    this.bind = function(event, obj, caller, one) {
        var fullEventName = 'event_' + event;
        if (observers[fullEventName] == undefined) {
            observers[fullEventName] = new Array;
        }
        if (observers[fullEventName][caller] == undefined) {
            observers[fullEventName][caller] = new Array();
        }
        observers[fullEventName][caller].push(
        {
            obj:obj,
            once: one ? true : false
        });
        if (app.debug.bind) console.log('Bind event: ', event, caller, one ? 'ONCE' : '');
    }

    //выполнить ивент
    this.fire = function(event, val) {
        var fullEventName = 'event_' + event;
        if (app.debug.fire) console.log('Fire event: ', event);
        if (observers[fullEventName] == undefined) {
            return false;
        }
        var caller;
        for (caller in observers[fullEventName]) {
            var iLen = observers[fullEventName][caller].length;
            for (var i = 0; i < iLen; i++) {
                if (typeof(observers[fullEventName][caller][i]) == 'object' && typeof(observers[fullEventName][caller][i].obj) == 'function') {
                    try {
                        observers[fullEventName][caller][i].obj(val);
                        if (observers[fullEventName][caller][i].once) {
                            delete observers[fullEventName][caller][i];
                            if (app.debug.observed) console.log('Event ONCE: ', event, caller);
                        } else {
                            if (app.debug.observed) console.log('Event: ', event, caller);
                        }
                    } catch (err) {
                        if (app.debug.observer_error) {
                            console.log('OBSERVER ERROR: ' + err.message);
                            console.log('OBSERVER ERROR DETAILS:');
                            console.log('EVENT NAME: ' + fullEventName);
                            console.log('EVENT CALLER:' + caller);
                            console.log('FUNCTION:');
                            console.log(observers[fullEventName][caller][i].obj);
                        }
                    }
                }
            }
        }
        return true;
    }

    //отписаться от события
    this.unbind = function(event, caller) {
        var fullEventName = 'event_' + event;
        if (observers[fullEventName] != undefined) {
            if (caller == undefined) {
                delete observers[fullEventName];
            } else {
                if (observers[fullEventName][caller] != undefined) {
                    delete observers[fullEventName][caller];
                }
            }
        }
    }

    //отписать от всех событий по ключу
    this.unbindAll = function(caller) {
        for (var fullEventName in observers) {
            if (observers[fullEventName][caller]) {
                delete observers[fullEventName][caller];
            }
        }
    }
}

function mlhItems(){
    this.check = function(id,onFalse,onOk) {
        var el = $(id);
        if (el.length) {
            if (onOk) onOk(el);
        } else onFalse(el);
    }
}

var app = {
    started: false,
    push: function(callback, params) {
        if (this.started) {
            callback(params);
            return;
        } else {
            app.main.bind('start', callback, "system");
        }
    },
    start: function() {
        app.started = true;
        app.main.fire('start', 'system');
    },
    debug: {
        fire: false,
        observed: false,
        observer_error: false,
        bind: false,
        ajax: false
    }
};

(function($) {
    app =  $.extend(app, {
        main: new mlhMain(),
        item: new mlhItems()
    });
    
})(jQuery);

$(document).ready(app.start);